package com.base.interview.devtest.util;

import com.base.interview.devtest.entity.UserEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.tomcat.util.codec.binary.Base64;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class SessionManager {
    private static final ThreadLocal<Long> threadUser = new ThreadLocal<>();

    public static void setThreadUser(Long userId) {
        threadUser.set(userId);
    }

    public static Long getThreadUser() {
        return threadUser.get();
    }

    private static long expire = 1000 * 60 * 30; // 30 minutes
    private static final Map<String, SessionEntity> sessions = new ConcurrentHashMap<>();
    private static final ScheduledExecutorService executors = Executors.newScheduledThreadPool(5);


    public static String login(UserEntity userEntity) {
        String token = generateToken();
        sessions.put(token, new SessionEntity(userEntity, System.currentTimeMillis()));
        return token;
    }

    public static void logout(String token) {
        sessions.remove(token);

    }

    public static UserEntity isLoggedIn(String token) {
        if (sessions.containsKey(token)) {
            return sessions.get(token).getUserEntity();
        }
        return null;
    }

    public static void refresh(String token) {
        SessionEntity sessionEntity = sessions.get(token);
        if (sessionEntity != null) {
            sessionEntity.setLastActiveTime(System.currentTimeMillis());
        }
    }


    static {
        SessionCleaner sessionCleaner = new SessionCleaner();
        executors.schedule(sessionCleaner, 1, TimeUnit.MINUTES);
    }


    private static String generateToken() {
        StringBuilder sb = new StringBuilder();
        sb.append(UUID.randomUUID().toString()).append(UUID.randomUUID().toString());
        String token = sb.toString().replaceAll("-", "").toUpperCase();
        return Base64.encodeBase64String(token.getBytes());
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private static class SessionEntity {
        private UserEntity userEntity;
        private Long lastActiveTime;
    }

    private static class SessionCleaner implements Runnable {

        @Override
        public void run() {
            System.out.println("start clean...");
            long now = System.currentTimeMillis();
            List<String> expiredKeys = new ArrayList<>();
            sessions.entrySet().stream().parallel().forEach(entry -> {
                String key = entry.getKey();
                SessionEntity sessionEntity = entry.getValue();
                if (now - sessionEntity.getLastActiveTime() >= expire) {
                    expiredKeys.add(key);
                }
            });
            expiredKeys.stream().parallel().forEach(expiredKey -> sessions.remove(expiredKey));
        }
    }

}
